package main

import (
	"encoding/json"
	"fmt"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/fsnotify/fsnotify"
)

const (
	broadcastPort     = "9999"           // 广播发现端口
	heartbeatInterval = 2 * time.Second  // 心跳包发送间隔
	modeSwitchTimeout = 15 * time.Second // 模式切换超时时间
	maxMessageSize    = 1024            // UDP 报文最大大小
)

type Mode int

const (
	ModeListening Mode = iota
	ModeMaster
	ModeSlave
)

type keepAliveConfig struct {
	IPAddress string `json:"ip_address"`
	Port      int    `json:"port"`
	PeerIP    string `json:"peer_ip"`
	SyncPort  int    `json:"sync_port"`
	SecretKey string `json:"secret_key"`
	Enable    bool   `json:"enable"`
}

type Message struct {
	Type    string      `json:"type"`
	Content interface{} `json:"content"`
}

type DiscoveryMessage struct {
	Type string `json:"type"`
	IP   string `json:"ip"`
	Port int    `json:"port"`
}

type metric struct {
	heartbeatsSent     int64
	heartbeatsReceived int64
}

var (
	keepAlive keepAliveConfig
	mode      Mode = ModeListening
	mu        sync.RWMutex
	metrics   metric
)

// ========== 启动模式切换 ==========
func startModeSwitch() {
	timer := time.NewTimer(modeSwitchTimeout)
	defer timer.Stop()

	for {
		select {
		case <-timer.C:
			mu.Lock()
			if atomic.LoadInt64(&metrics.heartbeatsReceived) == 0 {
				mode = ModeMaster
				go startMasterMode()
			} else {
				mode = ModeSlave
				go startSlaveMode()
			}
			mu.Unlock()
			return
		}
	}
}

// ========== 主机（Master）模式 ==========
func startMasterMode() {
	fmt.Println("切换到 Master 模式")
	go startDiscoveryBroadcast() // 广播自身 IP
	go startHeartbeat()          // 发送心跳包
	go syncConfig()              // 监听配置文件变化
}

func startDiscoveryBroadcast() {
	broadcastAddr := "255.255.255.255:" + broadcastPort
	udpAddr, err := net.ResolveUDPAddr("udp", broadcastAddr)
	if err != nil {
		fmt.Println("无法解析广播地址:", err)
		return
	}

	conn, err := net.DialUDP("udp", nil, udpAddr)
	if err != nil {
		fmt.Println("无法建立 UDP 广播连接:", err)
		return
	}
	defer conn.Close()

	for {
		message := DiscoveryMessage{
			Type: "discovery",
			IP:   keepAlive.IPAddress,
			Port: keepAlive.Port,
		}
		data, _ := json.Marshal(message)
		_, err := conn.Write(data)
		if err != nil {
			fmt.Println("广播发送失败:", err)
		}
		time.Sleep(2 * time.Second) // 每 2s 发送一次
	}
}

func startHeartbeat() {
	for {
		err := sendHeartbeat()
		if err != nil {
			fmt.Println("心跳发送失败:", err)
		}
		time.Sleep(heartbeatInterval)
	}
}

func sendHeartbeat() error {
	addr, err := net.ResolveUDPAddr("udp", keepAlive.PeerIP+":"+fmt.Sprintf("%d", keepAlive.Port))
	if err != nil {
		return err
	}
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		return err
	}
	defer conn.Close()

	message := Message{Type: "heartbeat", Content: ""}
	data, _ := json.Marshal(message)
	_, err = conn.Write(data)
	if err == nil {
		atomic.AddInt64(&metrics.heartbeatsSent, 1)
	}
	return err
}

// ========== 监听配置变化 ==========
func syncConfig() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Println("文件监控初始化失败:", err)
		return
	}
	defer watcher.Close()

	dir := "./selfpara"
	err = watcher.Add(dir)
	if err != nil {
		fmt.Println("监控目录失败:", err)
		return
	}

	for {
		select {
		case event, ok := <-watcher.Events:
			if !ok {
				return
			}
			if event.Op&fsnotify.Write == fsnotify.Write {
				fmt.Println("文件发生变化，开始同步:", event.Name)
			}
		case err, ok := <-watcher.Errors:
			if !ok {
				return
			}
			fmt.Println("文件监控错误:", err)
		}
	}
}

// ========== 从机（Slave）模式 ==========
func startSlaveMode() {
	fmt.Println("切换到 Slave 模式")
	go listenForMasterBroadcast() // 监听 Master 广播
	go startListener()            // 监听 Master 心跳包
}

func listenForMasterBroadcast() {
	addr, err := net.ResolveUDPAddr("udp", ":"+broadcastPort)
	if err != nil {
		fmt.Println("无法解析广播监听地址:", err)
		return
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		fmt.Println("无法监听广播端口:", err)
		return
	}
	defer conn.Close()

	buf := make([]byte, maxMessageSize)
	for {
		n, _, err := conn.ReadFromUDP(buf)
		if err != nil {
			fmt.Println("接收广播失败:", err)
			continue
		}

		var message DiscoveryMessage
		if err := json.Unmarshal(buf[:n], &message); err != nil {
			fmt.Println("解析广播数据失败:", err)
			continue
		}

		// 发现 Master，自动设置主机 IP 和端口
		if message.Type == "discovery" {
			fmt.Println("发现主机:", message.IP, "端口:", message.Port)
			mu.Lock()
			keepAlive.PeerIP = message.IP
			keepAlive.Port = message.Port
			mu.Unlock()

			// 开始心跳检测，确认主机是否有效
			go startHeartbeat()
		}
	}
}

// ========== 监听心跳包 ==========
func startListener() {
	addr, err := net.ResolveUDPAddr("udp", ":"+fmt.Sprintf("%d", keepAlive.Port))
	if err != nil {
		fmt.Println("解析 UDP 地址失败:", err)
		return
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		fmt.Println("UDP 监听失败:", err)
		return
	}
	defer conn.Close()

	buf := make([]byte, maxMessageSize)
	for {
		n, _, err := conn.ReadFromUDP(buf)
		if err != nil {
			fmt.Println("读取 UDP 数据失败:", err)
			continue
		}

		var message Message
		if err := json.Unmarshal(buf[:n], &message); err != nil {
			fmt.Println("解析消息失败:", err)
			continue
		}

		if message.Type == "heartbeat" {
			atomic.AddInt64(&metrics.heartbeatsReceived, 1)
			fmt.Println("收到心跳包")
		}
	}
}
